# coding:utf-8
# writingtime: 2022-8-3
# reference: https://doi.org/10.1007/s40815-021-01243-2

import numpy as np
from math import exp
from DistanceFunction.euclidean import Euclidean


class PCAEC:
    def __init__(self, dataList, membershipMatrix, clusterCenter, m=2):
        """
        function
        :param dataList: 样本向量
        :param membershipMatrix: 关系矩阵
        :param clusterCenter: 聚合中心
        :param m: 聚合参数
        """
        self.dataList = dataList
        self.membershipMatrix = membershipMatrix
        self.clusterCenter = clusterCenter
        self.m = m

    def getum(self, n):
        """
        function: 计算Um
        :param n: 第i个
        :return: Um的值
        """
        li = []
        for i in range(n):
            sum1 = 0
            for j in range(i, len(self.membershipMatrix[0])):
                sum1 += self.membershipMatrix[i][j] ** 2
            li.append(sum1)
        value = min(li)
        return value

    def getexp(self):
        """
        function: 计算指数部分的值
        :return:exp(...)
        """
        cluster_mean = self.getmean()
        # 计算beta_T
        beta_t = 0
        for i in self.clusterCenter:
            beta_t += Euclidean.getresult(i, cluster_mean) ** 2
        beta_t /= len(self.clusterCenter)

        sum1 = 0
        for i in range(len(self.clusterCenter)):
            li_temp = []
            for k in range(len(self.clusterCenter)):
                if i != k:
                    li_temp.append(Euclidean.getresult(self.clusterCenter[i], self.clusterCenter[k]) ** 2)
            sum1 += exp(-min(li_temp) / beta_t)
        return sum1

    def getmean(self):
        """
        function: 计算中心点向量的均值
        :return: 中心点向量的均值
        """
        cluster_mean = np.array([0 for _ in range(len(self.clusterCenter[0]))])
        for i in self.clusterCenter:
            cluster_mean += np.array(i)
        cluster_mean = list(cluster_mean / len(self.clusterCenter))
        return cluster_mean

    def getpcaec(self):
        """
        function: 计算PCAEC的值
        :return:
        """
        sum1 = 0
        for i in range(len(self.clusterCenter)):
            for j in range(len(self.dataList)):
                sum1 += (self.membershipMatrix[i][j] ** 2) / self.getum(i + 1)
        value = sum1 - self.getexp()
        return value

    @staticmethod
    def getresult(dataList, membershipMatrix, clusterCenter, m=2, a=2):
        """
        function: p评价函数
        :param dataList: 样本向量
        :param membershipMatrix: 评价矩阵
        :param clusterCenter: 中心点向量
        :param m: 聚合参数
        :return: PCAEC评价值
        """
        return PCAEC(dataList, membershipMatrix, clusterCenter, m).getpcaec()
